package com.example.demo;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.init.InitExecutor;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowItem;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.example.demo.common.exception.SentinelLimitException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class SentinelApplication {

    private static final Logger log = LoggerFactory.getLogger(SentinelApplication.class);

    public static void main(String[] args) {

        ConfigurableApplicationContext context = SpringApplication.run(SentinelApplication.class, args);

        // Sentinel资源名称
        // ContextUtil.enter("sentinel-demo");

        // 连接到控制台，与sentinel控制台通信
        System.setProperty("project.name", context.getEnvironment().getProperty("spring.application.name", "sentinel-demo"));
        System.setProperty("csp.sentinel.dashboard.server", context.getEnvironment().getProperty("sentinel.dashboard.server", "localhost:8868"));
        System.setProperty("csp.sentinel.api.port", context.getEnvironment().getProperty("sentinel.api.port", "8719"));
        InitExecutor.doInit();

        initFlowRules();
    }

    @GetMapping("/")
    @SentinelResource("index")
    public String index() {
        log.info("111");
        return "index!";
    }

    @GetMapping("/test")
    public String test() {

        Entry entry = null;
        try {
            entry = SphU.entry("test");

            /*您的业务逻辑 - 开始*/
            log.info("test!!!");
            /*您的业务逻辑 - 结束*/

            return "test!";
        } catch (BlockException e1) {
            /*流控逻辑处理 - 开始*/
            log.info("test_block!");
            /*流控逻辑处理 - 结束*/

            return "test_block!";
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
    }

    @GetMapping("/hello")
    @SentinelResource(value = "hello", blockHandler = "helloBlockHandler", fallback = "helloFallback")
    public R<Object> hello(@RequestParam("id") String id, @RequestParam("username") String username, @RequestParam("sex") int sex) {
        log.info("hello! id=" + id + ";username=" + username + ";sex=" + sex);
        return R.ok(new HashMap<String, String>() {
            {
                put("id", id);
                put("username", username);
                put("sex", String.valueOf(sex));
            }
        });
    }

    public R<Object> helloBlockHandler(String id, String username, int sex, BlockException e) throws SentinelLimitException {
        log.warn("hello blockHandler", e.toString());
        throw new SentinelLimitException("400", "hello被限流啦。。。id=" + id + ";username=" + username + ";sex=" + sex);
    }

    public String helloFallback(String id, String username, int sex, Throwable e) throws SentinelLimitException {
        log.warn("hello fallback", e.toString());
        throw new SentinelLimitException("400", "hello流量发生异常啦。。。id=" + id + ";username=" + username + ";sex=" + sex);
    }

    private static void initFlowRules() {

        List<ParamFlowRule> rules = ParamFlowRuleManager.getRules();

        //创建资源
        ParamFlowRule rule = new ParamFlowRule("hello")
            .setParamIdx(0)
            .setGrade(RuleConstant.FLOW_GRADE_QPS)
            .setDurationInSec(1)
            // .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
            // .setMaxQueueingTimeMs(600)
            .setCount(10);

        //参数例外项
        ParamFlowItem item1 = new ParamFlowItem().setObject("1").setClassType(String.class.getName()).setCount(1);
        ParamFlowItem item2 = new ParamFlowItem().setObject("2").setClassType(String.class.getName()).setCount(2);
        ParamFlowItem item3 = new ParamFlowItem().setObject("3").setClassType(String.class.getName()).setCount(3);

        List<ParamFlowItem> lists = new ArrayList<>(Arrays.asList(item1, item2, item3));
        rule.setParamFlowItemList(lists);
        rules.add(rule);
        ParamFlowRuleManager.loadRules(rules);
    }
}
